//go:generate goversioninfo -icon=resource/icon.ico -manifest=resource/goversioninfo.exe.manifest
package main

import (
	_ "embed"
	"fmt"
	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/app"
	"fyne.io/fyne/v2/canvas"
	"fyne.io/fyne/v2/container"
	"fyne.io/fyne/v2/data/binding"
	"fyne.io/fyne/v2/data/validation"
	"fyne.io/fyne/v2/dialog"
	"fyne.io/fyne/v2/layout"
	"fyne.io/fyne/v2/storage"
	"fyne.io/fyne/v2/theme"
	"fyne.io/fyne/v2/widget"
	"github.com/flopp/go-findfont"
	"github.com/goki/freetype/truetype"
	"io"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
)

//go:embed resource/Icon.png
var icon []byte

//go:embed resource/logo.png
var logo []byte

//go:embed resource/zhifubao.png
var zfb []byte

//go:embed resource/weixin.png
var wx []byte

func main() {
	a := app.New()
	a.SetIcon(fyne.NewStaticResource("icon", icon))
	w := a.NewWindow("文件分割")

	//http://www.3h3.com/soft/162663.html
	//需要分割的文件信息
	//路径 输入框 浏览
	//文件名称	文件大小
	//分割参数设置
	//按文件大小分割：文字输入框	单位选择	/个文件
	//按照文件数量分割大小：文字输入框 个文件
	//生成后文件目录	生成文件个数

	//主界面框架布局
	MainShow(w)
	//尺寸
	w.Resize(fyne.Size{Width: 800, Height: 500})
	//窗口可缩放
	w.SetFixedSize(false)
	w.ShowAndRun()
}

// 初始化
func init() {
	fontPath, err := findfont.Find("SIMYOU.TTF")
	if err != nil {
		panic(err)
	}
	fmt.Printf("Found 'arial.ttf' in '%s'\n", fontPath)

	// load the font with the freetype library
	// 原作者使用的ioutil.ReadFile已经弃用
	fontData, err := os.ReadFile(fontPath)
	if err != nil {
		panic(err)
	}
	_, err = truetype.Parse(fontData)
	if err != nil {
		panic(err)
	}
	os.Setenv("FYNE_FONT", fontPath)
}

var f1 = binding.NewString()
var fileName = binding.NewString()

// 文件总大小
var fileSize = binding.NewInt()

// 单个大小
var settleSplitSize = binding.NewString()

// 数量
var settleSplitNum = binding.NewString()

// 单位
var settleUnit = binding.NewString()

// 类型
var settleType = binding.NewString()

var numberLable = binding.NewString()

// 单个文件大小
var fileSplitOneSize = binding.NewInt()

// 文件夹名称
var fileFolderName = ""

// 进度条
var progressBar *widget.ProgressBar

// 主窗口
func MainShow(w fyne.Window) {
	progressBar = widget.NewProgressBar()

	fileNameLable := widget.NewLabel("文件名称：")
	fileSizeLable := widget.NewLabel("文件大小：")

	fileFolderLable := widget.NewLabel("生成后文件目录：")

	fileNumberLable := widget.NewLabelWithData(numberLable)

	// 保存输入文件路径
	//f1 := binding.NewString()
	fileEntity := widget.NewEntryWithData(f1)
	wf1 := container.NewBorder(nil, nil, nil,
		widget.NewButtonWithIcon("", theme.FileTextIcon(), func() {
			d := dialog.NewFileOpen(func(uc fyne.URIReadCloser, e error) {
				log.Println("change file")
				if uc == nil {
					return
				}
				f1.Set(uc.URI().String()[7:])
			}, w)
			luri, _ := storage.ListerForURI(storage.NewFileURI("."))
			d.SetFilter(storage.NewExtensionFileFilter([]string{".txt", ".log"}))
			d.SetLocation(luri)
			d.Show()
		}), fileEntity)
	//文件改变
	fileEntity.OnChanged = func(url string) {
		f1.Set(url)
		log.Println("file change:" + url)
		info, err := os.Stat(url)
		if err != nil {
			fmt.Println("os.Stat err =", err)
			return
		}
		//后缀
		suffix := filepath.Ext(fileEntity.Text)
		//新文件夹名
		fileFolderName = strings.ReplaceAll(info.Name(), suffix, "")

		fileNameLable.SetText("文件名称：" + info.Name())
		fileFolderLable.SetText("生成后文件目录：" + fileFolderName)
		fileSize.Set(int(info.Size()))
		fileSizeLable.SetText("文件大小：" + strconv.FormatInt(info.Size(), 10))
		onSettingChange()
	}

	topIn := container.NewBorder(nil, nil, widget.NewLabel("文件名称"), nil, wf1)

	line3 := container.New(layout.NewGridLayout(2), fileNameLable, fileSizeLable)

	radio1 := widget.NewRadioGroup([]string{"按大小分割"}, nil)
	radio2 := widget.NewRadioGroup([]string{"按数量分割"}, nil)
	radio1.SetSelected("按大小分割")
	radio1.OnChanged = func(value string) {
		log.Println("Radio1 set to", value)
		if value == "按大小分割" {
			settleType.Set(value)
			onSettingChange()
			radio1.SetSelected("按大小分割")
			radio2.SetSelected("")
		} else {
			radio1.SetSelected("")
			radio2.SetSelected("按数量分割")
		}
	}
	radio2.OnChanged = func(value string) {
		log.Println("Radio2 set to", value)
		if value == "按数量分割" {
			settleType.Set(value)
			onSettingChange()
			radio1.SetSelected("")
			radio2.SetSelected("按数量分割")
		} else {
			radio1.SetSelected("按大小分割")
			radio2.SetSelected("")
		}
	}
	//分割大小选择
	var select1 *widget.Select = widget.NewSelect([]string{"kb", "mb"}, func(value string) {
		log.Println("select set to", value)
		settleUnit.Set(value)
		onSettingChange()
	})
	//设置默认选中
	select1.SetSelectedIndex(0)
	settleSplitSize.Set("100")

	entry2 := widget.NewEntryWithData(settleSplitSize)
	entry2.Validator = validation.NewRegexp("^[0-9]+$", "请输入数字")
	entry3 := widget.NewEntryWithData(settleSplitNum)
	entry3.Validator = validation.NewRegexp("^[0-9]+$", "请输入数字")
	label3 := widget.NewLabel("/个文件")
	label4 := widget.NewLabel("个文件")

	entry2.OnChanged = func(s string) {
		settleSplitSize.Set(s)
		onSettingChange()
	}
	entry3.OnChanged = func(s string) {
		settleSplitNum.Set(s)
		onSettingChange()
	}

	line4 := container.New(layout.NewGridLayout(2), fileFolderLable, fileNumberLable)

	card1 := widget.NewCard("需要分割的文件信息", "", container.NewVBox(topIn, line3))
	card2 := widget.NewCard("分割参数设置", "", container.NewVBox(
		container.NewBorder(nil, nil, radio1, container.NewHBox(select1, label3), entry2),
		container.NewBorder(nil, nil, radio2, label4, entry3),
		line4,
	),
	)
	splitButton := widget.NewButton("切割文件", func() {
		log.Println("切割文件")
		var p, _ = f1.Get()
		file, err := os.Open(p)
		if err != nil {
			dialog.NewInformation("提醒", "打开文件失败："+p, w).Show()
			log.Println("打开文件失败:", p)
			return
		}
		defer file.Close()
		var size, _ = fileSplitOneSize.Get()
		if size <= 0 {
			dialog.NewInformation("提醒", "分割参数有误!", w).Show()
			return
		}
		folder := filepath.Dir(p) + fileFolderName + "\\"
		SplitFile(file, size, folder)
		dialog.NewCustomConfirm("提醒", "打开文件夹", "好的", container.NewVBox(widget.NewLabel("文件分割成功!分割后文件路径："+folder)), func(b bool) {
			log.Println(b)
			if b {
				exec.Command(`cmd`, `/c`, `explorer`, folder).Start()
			}
		}, w).Show()
		//dialog.NewInformation("提醒", "文件分割成功!分割后文件路径："+folder, w).Show()
	})
	exitButton := widget.NewButton("退出", func() {
		log.Println("退出")
		w.Close()
	})

	entLine := container.NewBorder(nil, nil, nil, container.NewHBox(splitButton, exitButton), container.NewHBox(widget.NewLabel("")))

	imgLogo := canvas.NewImageFromResource(fyne.NewStaticResource("logo", logo))
	logoLine := container.NewBorder(nil, nil, container.NewGridWrap(fyne.NewSize(200, 73), imgLogo), nil, getPayCode())

	cent := container.NewVBox(card1,
		card2,
		progressBar,
		entLine,
		logoLine,
	)
	w.SetContent(cent)
}

// 参数改变重新计算
func onSettingChange() {
	log.Println("onSettingChange")
	progressBar.SetValue(0)
	//判断类型
	var stype, _ = settleType.Get()
	if stype == "按数量分割" {
		//获取设置分割文件数量
		var snum, _ = settleSplitNum.Get()
		log.Println("数量：" + snum)
		numberLable.Set("生成文件个数：" + snum)
		var nsnum, _ = strconv.Atoi(snum)
		if nsnum > 0 {
			//计算单个文件大小
			sss := 0
			totalsize, _ := fileSize.Get()
			var nsnum, _ = strconv.Atoi(snum)
			if totalsize%nsnum > 0 {
				sss++
			}
			sss = sss + (totalsize / nsnum)
			fileSplitOneSize.Set(sss)
		} else {
			fileSplitOneSize.Set(nsnum)
		}
	} else {
		//文件大小
		//单个文件大小
		var ss, _ = settleSplitSize.Get()
		//设置单个文件大小
		var sss, _ = strconv.Atoi(ss)
		var su, _ = settleUnit.Get()
		log.Println("单位" + su)
		if su == "kb" {
			sss = sss * 1024
		} else if su == "mb" {
			sss = sss * 1024 * 1024
		}
		log.Println("大小" + strconv.Itoa(sss))
		if sss > 0 {
			//计算文件总数量
			totalNum := 0
			totalsize, _ := fileSize.Get()
			if totalsize%sss > 0 {
				totalNum++
			}
			totalNum = totalNum + (totalsize / sss)
			fileSplitOneSize.Set(sss)
			numberLable.Set("生成文件个数：" + strconv.FormatInt(int64(totalNum), 10))
			log.Println("数量" + strconv.Itoa(totalNum))
		} else {
			fileSplitOneSize.Set(0)
		}
	}
}

// 分割文件
func SplitFile(file *os.File, size int, fileFolderName string) {
	finfo, err := file.Stat()
	if err != nil {
		fmt.Println("获取文件信息失败:", file, size)
	}
	fmt.Println(finfo, size)

	_, err = os.Stat(fileFolderName)
	if os.IsNotExist(err) {
		log.Println("目录【" + fileFolderName + "】不存在!")
		err := os.Mkdir(fileFolderName, os.ModePerm)
		if err != nil {
			log.Println("创建目录【" + fileFolderName + "】失败!")
			return
		}

	}

	//每次最多拷贝1m
	bufsize := 1024 * 1024
	if size < bufsize {
		bufsize = size
	}
	buf := make([]byte, bufsize)
	num := (int(finfo.Size()) + size - 1) / size
	fmt.Println(num, len(buf))
	for i := 0; i < num; i++ {
		progressBar.SetValue(float64((i + 1) / num))
		copylen := 0
		newfilename := fileFolderName + finfo.Name() + strconv.Itoa(i)
		newfile, err1 := os.Create(newfilename)
		if err1 != nil {
			fmt.Println("创建文件失败", newfilename)
		} else {
			fmt.Println("创建文件:", newfilename)
		}
		for copylen < size {
			n, err2 := file.Read(buf)
			if err2 != nil && err2 != io.EOF {
				fmt.Println(err2, "读取文件失败:", file)
				break
			}
			if n <= 0 {
				break
			}
			//fmt.Println(n, len(buf))
			//写文件
			w_buf := buf[:n]
			newfile.Write(w_buf)
			copylen += n
		}
	}
	return
}

// 收款码
func getPayCode() *fyne.Container {
	wxImg := canvas.NewImageFromResource(fyne.NewStaticResource("wx", wx))
	zfbImg := canvas.NewImageFromResource(fyne.NewStaticResource("zfb", zfb))
	return container.NewGridWithColumns(5, container.NewCenter(widget.NewLabel("赞助一下")),
		container.NewGridWrap(fyne.NewSize(73, 73), wxImg),
		container.NewGridWrap(fyne.NewSize(73, 73), zfbImg),
	)
	//return container.NewHBox(container.NewGridWrap(fyne.NewSize(73, 73), wxImg), container.NewGridWrap(fyne.NewSize(73, 73), zfbImg))
}
